<html>
<head><meta charset="utf-8"><title>Fixing the dyn-assoc RFC · general · Zulip Chat Archive</title></head>
<h2>Stream: <a href="https://rust-lang.github.io/zulip_archive/stream/122651-general/index.html">general</a></h2>
<h3>Topic: <a href="https://rust-lang.github.io/zulip_archive/stream/122651-general/topic/Fixing.20the.20dyn-assoc.20RFC.html">Fixing the dyn-assoc RFC</a></h3>

<hr>

<base href="https://rust-lang.zulipchat.com">

<head><link href="https://rust-lang.github.io/zulip_archive/style.css" rel="stylesheet"></head>

<a name="207169483"></a>
<h4><a href="https://rust-lang.zulipchat.com#narrow/stream/122651-general/topic/Fixing%20the%20dyn-assoc%20RFC/near/207169483" class="zl"><img src="https://rust-lang.github.io/zulip_archive/assets/img/zulip.svg" alt="view this post on Zulip" style="width:20px;height:20px;"></a> Goat <a href="https://rust-lang.github.io/zulip_archive/stream/122651-general/topic/Fixing.20the.20dyn-assoc.20RFC.html#207169483">(Aug 17 2020 at 17:06)</a>:</h4>
<p>A few months ago, I was working with trait objects and stumbled upon the restrictions around associated constants and functions in traits (you can't have them and use the trait in a trait object at the same time). Making the trait artificially object-safe similarly to <a href="https://docs.rs/erased-serde"><code>erased-serde</code></a> was a solution that I stumbled upon, and it was pretty logical, convenient and 100% safe, stable and straightforward for my purposes. (The original project itself was put on hold in favor of something more promising and achievable for me.)</p>
<p>The only disadvantage about this approach was that it was a new type of boilerplate which was used solely to work around a language restriction. So to address this problem, I decided to write an RFC myself, proposing a simple solution at first. The RFC was published under <a href="https://github.com/rust-lang/rfcs/pull/2886">PR #2886</a>.</p>
<p>As I found out later, the RFC that I wrote initially was simply too shallow and naive and that there are certain problems I overlooked. On top of that, question of syntax choice was raised in the RFC which has not been conclusively discussed, mainly because the design issues were <em>considerably more severe</em>.</p>
<p>Those issues are simpler to explain by explaining the RFC itself. The simplest example is this:</p>
<div class="codehilite"><pre><span></span><code><span class="c1">// In present Rust, this trait is not object-safe, something that this RFC changes.</span>
<span class="k">trait</span><span class="w"> </span><span class="n">ThingDoer</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="k">fn</span> <span class="nf">do_a_thing</span><span class="p">();</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
<span class="k">struct</span> <span class="nc">DefaultThingDoer</span><span class="p">;</span><span class="w"></span>
<span class="k">impl</span><span class="w"> </span><span class="n">ThingDoer</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">DefaultThingDoer</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="k">fn</span> <span class="nf">do_a_thing</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">        </span><span class="n">println</span><span class="o">!</span><span class="p">(</span><span class="s">&quot;Did a thing!&quot;</span><span class="p">);</span><span class="w"></span>
<span class="w">    </span><span class="p">}</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>

<span class="k">fn</span> <span class="nf">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">thingdoer</span>: <span class="nb">Box</span><span class="o">&lt;</span><span class="k">dyn</span><span class="w"> </span><span class="n">ThingDoer</span><span class="o">&gt;</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">Box</span>::<span class="n">from</span><span class="p">(</span><span class="n">DefaultThingDoer</span><span class="p">);</span><span class="w"></span>
<span class="w">    </span><span class="c1">// Even though do_a_thing() does not take &amp;self, thingdoer is used to dynamically dispatch the concrete</span>
<span class="w">    </span><span class="c1">// implementation, which is why method syntax is used.</span>
<span class="w">    </span><span class="n">thingdoer</span><span class="p">.</span><span class="n">do_a_thing</span><span class="p">();</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>


<p>Here's the problem:</p>
<div class="codehilite"><pre><span></span><code><span class="c1">// See previous example for definitions of ThingDoer and DefaultThingDoer</span>
<span class="k">fn</span> <span class="nf">thing_doer_convenience_function</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span><span class="p">(</span><span class="n">x</span>: <span class="kp">&amp;</span><span class="nc">T</span><span class="p">,</span><span class="w"> </span><span class="n">y</span>: <span class="kp">&amp;</span><span class="nc">T</span><span class="p">)</span><span class="w"></span>
<span class="k">where</span><span class="w"> </span><span class="n">T</span>: <span class="nc">ThingDoer</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="o">?</span><span class="nb">Sized</span><span class="w">  </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="c1">// This function is valid in present Rust and is not aware that this RFC exists</span>
<span class="w">    </span><span class="n">T</span>::<span class="n">do_a_thing</span><span class="p">()</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
<span class="k">struct</span> <span class="nc">SpecialThingDoer</span><span class="p">;</span><span class="w"></span>
<span class="k">impl</span><span class="w"> </span><span class="n">ThingDoer</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">SpecialThingDoer</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="k">fn</span> <span class="nf">do_a_thing</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">        </span><span class="n">println</span><span class="o">!</span><span class="p">(</span><span class="s">&quot;Did a thing in a very special way!&quot;</span><span class="p">);</span><span class="w"></span>
<span class="w">    </span><span class="p">}</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
<span class="k">fn</span> <span class="nf">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">DefaultThingDoer</span><span class="p">;</span><span class="w"></span>
<span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">b</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">SpecialThingDoer</span><span class="p">;</span><span class="w"></span>
<span class="w">    </span><span class="c1">// Which one of the implementations are used after this function is called?</span>
<span class="w">    </span><span class="n">thing_doer_convenience_function</span><span class="p">(</span><span class="o">&amp;</span><span class="n">a</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="o">&amp;</span><span class="k">dyn</span><span class="w"> </span><span class="n">ThingDoer</span><span class="p">,</span><span class="w"> </span><span class="o">&amp;</span><span class="n">b</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="o">&amp;</span><span class="k">dyn</span><span class="w"> </span><span class="n">ThingDoer</span><span class="p">);</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>


<p>In other words, a generic parameter <code>T</code> with a trait bound for <code>Trait</code> does not need to and cannot use a value of type <code>T</code> to call <em>associated functions</em> from <code>Trait</code> or fetch its constants, but if trait objects are involved and there's multiple of them, that's totally impossible.</p>
<p>In an effort to somehow work around this issue, I explained in the RFC that using a trait object as <code>T</code> in such a case would result in an error. This led to another unexpected twist in the RFC's development process (unexpected for me, at least): that solution was also wrong because <strong>I couldn't just say "that's gonna an error" to magically fix everything</strong>. Errors during monomorphization are simply not a thing.</p>
<p>At this point, the RFC seemed to be a dead end to me, as I couldn't possibly find a solution to this. A viable-ish one that I came up with was that object safety rules for traits would have two tiers: "object safe" and "generically object safe".</p>
<p>The second one, "generically object safe", represents the exact concept of "object safe" as it is now (no associated functions or constants, <em>period</em>) and is required to put <code>dyn Trait</code> in place of <code>T</code> if the function ever refers to <code>T</code> directly (that'd require adding more metadata to the function's compiled output, I assume).</p>
<p>The first one, "object safe", refers to traits which <em>do</em> have associated functions and/or constants, which would be usable in functions which do not require "generic object safety" (i.e. never refer to <code>T</code> itself and instead use the new syntax for using associated members of values' actual concrete types).</p>
<p>While I could've implemented those new ideas into the RFC repo right now, I still feel a little unsure about all the edge cases which have come up. I'd like to settle them down in this topic. Any new ideas would also be greatly appreciated! <span aria-label="rocket" class="emoji emoji-1f680" role="img" title="rocket">:rocket:</span></p>



<hr><p>Last updated: Aug 07 2021 at 22:04 UTC</p>
</html>